package team.nmsg.ge.system.init.shiro;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.StringUtils;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMethod;

import com.alibaba.fastjson.JSONObject;

import team.nmsg.ge.system.util.ServerConstants;
import team.nmsg.ge.system.util.ServerParams;

/**
 * NMS Shiro 请求统一拦截器 实现了相同用户重复登陆T出已登录的一个
 * @author Guodeqi
 *
 */
public class SysFormAuthenticationFilter extends FormAuthenticationFilter implements ServerConstants {

	private static final Logger log = LoggerFactory.getLogger(SysFormAuthenticationFilter.class);

	/**
	 * 未登录时处理 拒绝
	 */
	@Override
	protected boolean onAccessDenied(ServletRequest request,
			ServletResponse response) throws Exception {
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		HttpServletResponse httpResponse = (HttpServletResponse) response;
		
		if (RequestMethod.OPTIONS.toString().equals(WebUtils.toHttp(request).getMethod())) {
			writeJson2(WebUtils.toHttp(response));
			return false;
		}
		//重定向跨域
		WebUtils.toHttp(response).setHeader("Access-Control-Allow-Origin", "*");
		

		Subject subject = getSubject(request, response);
		Session session = subject.getSession();
		//未登录
		Object principal = subject.getPrincipal();
		if ( principal == null || !subject.isAuthenticated()) {
			if ( isAjaxRequest(httpRequest) ) {
				//"您尚未登录或登录时间过长,请重新登录!"
				JSONObject jsonObject = new JSONObject();
				jsonObject.put(ServerParams.NOLOGIN_KEY, true);
				writeJson(jsonObject  , httpResponse);
			} else {
				saveRequestAndRedirectToLogin(request, response);
			}
		} else {
			//被T出
			Object isKickOut = session.getAttribute(SESSION_KEY_KICKOUT);
			//如果被打上踢出标记，则踢出
			if(isKickOut!= null && isKickOut.toString().equals("true")  ){
				subject.logout();
				if (isAjaxRequest(httpRequest)) {
					JSONObject retJson = new JSONObject();
					retJson.put(KEY_KICKOUT, true);
					writeJson(retJson, httpResponse);
				}else{
					WebUtils.issueRedirect(request, response, "/login?"+KEY_KICKOUT+"=true");
				}
				return false;
			}
			
			//没有权限
			if ( isAjaxRequest(httpRequest)) {
				//您没有权限
				JSONObject jsonObject = new JSONObject();
				jsonObject.put(ServerParams.NOPERMIT_KEY, true);
				writeJson(jsonObject  ,  httpResponse );
			} else {
				String unauthorizedUrl = ServerParams.NOAUTH_URL ; 	
				if (StringUtils.hasText(unauthorizedUrl)) {
					WebUtils.issueRedirect(request, response, unauthorizedUrl);
				} else {
					WebUtils.toHttp(response).sendError(401);
				}
			}
		}
		return false;
	
	}
	
	@Override
	protected boolean isAccessAllowed(ServletRequest request,  ServletResponse response, Object mappedValue) {
		
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		HttpServletResponse httpResponse = (HttpServletResponse) response;
		Subject subject = getSubject(request, response);
		
		Session session = subject.getSession();
		
		Object isKickOut = session.getAttribute(SESSION_KEY_KICKOUT);
		//如果被打上踢出标记，则拒绝
		if(isKickOut!= null && isKickOut.toString().equals("true")  ){
			return false;
		}
		
		try {
			String requestURI = httpRequest.getRequestURI();
			String dirName = requestURI.substring(1);
			int indexOf = dirName.indexOf("/");
			if( indexOf!=-1 ){
				dirName = dirName.substring(0 , indexOf );
			}
			if( ServerParams.denyDir.contains(dirName)){
				return false;
			}
		} catch (Exception e) {
			log.error("" , e);
		}
		
		return super.isAccessAllowed(httpRequest, httpResponse, mappedValue);
	}  

	
	public static boolean isAjaxRequest(HttpServletRequest  httpRequest ){
		   String header = httpRequest.getHeader("X-Requested-With"); 
		    if (header != null && "XMLHttpRequest".equals(header)) 
		        return true; 
		    else 
		        return false; 
	}
	
	public static void writeJson(JSONObject retJson ,  HttpServletResponse httpResp){
		httpResp.setContentType("application/json; charset="+ServerParams.ENCODE);
		httpResp.setHeader("Cache-Control", "no-cache");
		PrintWriter pw = null;
		try {
			pw = httpResp.getWriter();
			pw.print(retJson);
			pw.flush();
		} catch (IOException e) {
			log.error("" , e);
		} finally {
			pw.close();
		}
	}
	
	private static void writeJson2(HttpServletResponse httpResp) {
		httpResp.setContentType("application/json; charset=UTF-8");
		httpResp.setHeader("Access-Control-Allow-Headers",  "JSESSIONID" );
		httpResp.setHeader("Access-Control-Allow-Methods", "GET,HEAD,POST");
		httpResp.setHeader("Access-Control-Allow-Origin", "*");
		httpResp.setHeader("Access-Control-Max-Age", "1800");
		httpResp.setHeader("Allow", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH");
		httpResp.setHeader("Content-Length", "0");
		httpResp.setHeader("Vary", "Origin");
		httpResp.setHeader("Vary", "Access-Control-Request-Method");
		httpResp.setHeader("Vary", "Access-Control-Request-Headers");
		PrintWriter pw = null;
		try {
			pw = httpResp.getWriter();
//            pw.print(retJson);
			pw.flush();
		} catch (IOException e) {
			log.error("", e);
		} finally {
			pw.close();
		}
	}
	
	
}